﻿// 15. 浮点型、字符型、转义字符、字符串、布尔.cpp 

//浮点型（实数型）
//C++浮点型分三种：float（单精度）、double（双精度）、long double（扩展精度）。
//三者的区别是表示有效数字的范围不同。

/*
//   数据类型            占用空间          有效数字范围
      float               4 字节            7 位有效数字           8 位
      double              8 字节            15～16 位有效数字      17 位
      long double         不少于 double     不低于 double          17 位
注意：
 在 VS 和 Linux 中，long double 占用的内存空间分别是 8 和 16 字节。
 有效数字包括了小数点前面和后面的数字。
 C++缺省显示 6 位有效数字，如果要显示更多的有效数字，可以用 printf()函数。
 浮点数的存储方法和整数不一样，比较复杂，如无必要，不用研究。（百度“为什么浮点数的小数位很多”、“为什么浮点数不精确”）
 在实际开发中，用整数代替浮点数，整数的运算更快，精度更高。9223372036854775807
*/

//字符型的基本概念
/*
字符型（char）占用的内存空间是 1 个字节，书写用单引号包含。
在内存中，不存放字符本身，而是存放与它对应的编码，即 ASCII 码。
ASCII（American Standard Code for Information Interchange，美国信息交换标准代码）是现今
最通用的单字节编码方案，包含了 33 个控制字符（具有特殊含义无法显示的字符）和 95 个可显示字符。
 'X' -> 88 01011000 
 'a'->  97 01100001 
 '3'->  51 00110011

a）32 是空格。
b）48～57 是 0 到 9 十个阿拉伯数字；
c）65～90 是 26 个大写英文字母；
d）97～122 号是 26 个小写英文字母；
e）其余的是一些标点符号、运算符号等；
f）第 127 个字符表示的是键盘上的删除键。
*/

//字符的本质
/*
a）字符的本质是整数，取值范围是 0～127。
b）在书写的时候可以用单引号包含，也可以用整数。
c）如果书写的时候用单引号包含，程序执行的时候，将把符号解释为对应的整数。
d）显示的时候，把整数解释为对应的符号，也可以直接显示整数。
d）可以与整数进行任何运算，运算的时候，书写方式可以用字符，也可以用整数。
e）C++为什么没有提供 1 字节的整型？
f）字符型也可以用 unsigned 修饰，意义何在？
*/

//转义字符
/*
在 C++程序中，使用转义字符的原因有两个：
 控制字符没有符号，无法书写，只能用其它的符号代替。
 某些符号已被 C++征用，语义冲突，只能用其它的符号代替。

 ASCII码值           转义字符                含义
   0                   \0                   空，给字符型变量赋值时可以直接书写 0。
   10                  \n                   换行(LF) ，将当前位置移到下一行开头。
   13                  \r                   回车(CR) ，将当前位置移到本行开头
   9                   \t                   水平制表(HT) （跳到下一个 TAB 位置）
   92                  \\                   斜线
   34                  \"                   双引号，书写字符时不必转义。
   39                  \'                   单引号，书写字符串中不必转义。
   7                   \a                   警报
   8                   \b                   退格(BS) ，将当前位置移到前一列
   12                  \f                   换页(FF)，将当前位置移到下页开头
   11                  \v                   垂直制表(VT)
*/

//C++11 的原始字面量
/*
原始字面量（值）可以直接表示字符串的实际含义，不需要转义和连接。
语法：R"(字符串的内容)" 
      R"xxx(字符串的内容)xxx"
*/

/*
#include<stdio.h>
#include <iostream>
using namespace std;
int main()
{
    // float 7 位有效数字；double 15～16 位有效数字；long double 不低于 double
    float a = 123.145; cout << "a = "<<a<<endl;
    double b = 12345123056789.45; cout << "b = " << b << endl;
    long double c = 12345126789.459; cout << "c = " << c << endl;
    printf("a = %lf\n", a);
    printf("b = %lf\n", b);
    printf("c = %lf\n", c);

    // 字符型（char）占用的内存空间是 1 个字节，书写用单引号包含。
    int vx = 'X'; cout << "vx = " << vx << endl;
    cout << "sizeof(vx) = " << sizeof(vx) << endl;
    int vy = 'a'; cout << "vy = " << vy << endl;
    // 'X' -> 88 'a'->97

    char y = '\"'; cout << "y = " << y << endl;
    // 水平制表符用于对齐输出的内容。
    cout << "1\t西施"; cout << "100\t 西瓜\n"; cout << "1000\t 冰冰\n";

    // 使用转义的方法输出字符串
    string path = "C:\\Program Files\\Microsoft OneDrive\\tail\\nation"; cout << "path = " << path << endl;

    // 使用 C++11 原始字面量
    // R"xxx(字符串的内容)xxx" 
    string path1 = R"aa(C:\Program Files\Microsoft OneDrive\tail\nation)aa"; cout << "path1 = " << path1 << endl;
    string str = R"aa(
                 <no>0001</no>
                 <name>西施</name>
                 <sc>火树银花</sc>
                 <yz>沉鱼</yz>
                 <age>23</age>
                 <weight>48.5</weight>
                 <height>170</height>)aa"; 
    cout << "str = " << str << endl;
}
*/

  

//字符串型
/*
C++风格字符串：string 变量名 = "字符串的内容";
C 风格字符串：char 变量名[] = "字符串的内容";
C 风格字符串的本质是字符数组，C++风格字符串的本质是类，它封装了 C 风格字符串。
 C++风格字符串的常用操作：
 赋值：变量名 = "字符串的内容"; 
 拼接：变量名 = 变量名 + "字符串的内容一" + "字符串的内容一" + ...... + "字符串的内容 n";
如果字符串的内容都是常量，不要写加号（ + ），如果内容很长，可以分成多行书写。
 比较：支持 == 、 != 、 > 和 < 关系运算符，常用的是 == 和 != 。
*/

//布尔型
/*
在 C 和 C++中，关系运算和逻辑运算的结果有两种：真和假。
C 语言用 0 表示假，非 0 表示真。
为了提高代码的可读性，C++新增了 bool 类型，占用 1 字节的内存，用 true 表示真，false 表示假。
bool 类型本质上是 1 字节的整数（unsigned char），取值只有 1 和 0。
在程序中，书写的时候可以用 true 和 false，编译器把它们解释为 1 和 0。
如果对 bool 型变量赋非 0 的值，将转换成 1。
用 cin 输入和 cout 输出的时候，仍是 1 和 0，不会被解释为 true 和 false。
*/

//数据类型的转换
/*
计算机进行运算时，要求各操作数的类型具有相同的大小和存储方式。
在实际开发中，不同类型的数据进行混合运算是基本需求。
自动类型转换：某些类型的转换编译器可以隐式的进行，不需程序员干预。
强制类型转换：有些类型的转换需要程序员显式指定。

1）自动类型转换
不同数据类型的差别在于取值范围和精度，数据的取值范围越大，精度越高。
整型从低到高：
char -> short -> int -> long -> long long
浮点型从低到高：
float -> double -> long double
自动类型转换的规则如下：
 如果一个表达式中出现了不同类型操作数的混合运算，较低类型将自动向较高类型转换。
 当表达式中含有浮点型操作数时，所有操作数都将转换为浮点型。
 赋值运算的右值类型与左值类型不一致时，将右值类型提升 / 降低为左值类型。
 赋值运算右值超出了左值类型的表示范围，把该右值截断后赋给左值，所得结果可能毫无意义。

2）强制类型转换
为了让程序设计更灵活，转换的目的更清晰，C++提供了强制类型转换的方法，也称之为显式转换。
强制类型转换的语法：(目标类型)表达式或目标类型(表达式)
注意：
 如果使用强制转换，表示程序员已有明确的目的。
 如果转换的行为不符合理，后果由程序员承担。
 如果采用了强制类型转换，编译的告警信息将不再出现。
 类型转换运算符的优先级比较高，如果没把握就加括号。
*/

//数据类型的别名 typedef
/*
创建数据类型的别名有两个目的：
 为名称复杂的类型创建别名，方便书写和记忆。
 创建与平台无关的数据类型，提高程序的兼容性。
语法：typedef 原数据类型名 别名;
C++11 还可以用 using 关键字创建数据类型的别名。
语法：using 别名 = 原数据类型名;

*/


#include<iostream>
using namespace std;
int main()
{
    string str = "西施";                                         // 声明字符串变量并初始化
    str = "冰冰小妹妹";                                          // 对字符串变量重新赋值。
    cout << "请输入超女姓名：";
    cin >> str;                                                  // 从控制台输入数据，保存在变量 str中。
    if (str == "冰冰")
        cout << "冰冰这样的妹妹是我喜欢的类型\n";                // 用==可以判断两个字符串是否相同
    if (str != "冰冰")
        cout << "既然不是我喜欢的类型，那就不玩了\n"<<endl;      // 用!=可以判断两个字符串是否不相同

    str = "姓名：" + str + ",这是我的现女友";                    // 用+可以拼接多个字符串
    cout << "str = " << str << endl << endl;

    // 如果字符串的内容都是常量，不要写加号（+），如果内容很长，可以分成多行书写。
    str = "姓名：" "幂幂" ",这是我的前女友\n";
    cout << "str = " << str << endl<<endl;

   //布尔类型
    bool b = 1;
    cout << " b + b = " << b + b << endl;                       // 将显示 2
    // 如果对 bool 型变量赋非 0 的值，将转换成 1。
    bool c = 30;
    cout << " c = " << c << endl << endl;

    // 找到布尔变量 b 的内存，把里面的数据强制为 8。
    char* pc = (char *) & b;
    *pc = 8;
    cout << "b = " << b <<endl;

    // 如果一个表达式中出现了不同类型操作数的混合运算，较低类型将自动向较高类型转换。
    char vx = 30;
    int vy = 102400;
    long long vz = 15000000000001;
    cout << "vx + vy + vz = " << vx + vy + vz << endl;

    // 当表达式中含有浮点型操作数时，所有操作数都将转换为浮点型。
    cout << "8 / 3 = " << (double)8 / 3 << endl;

    // 赋值运算的右值类型与左值类型不一致时，将右值类型提升 / 降低为左值类型。
    // 赋值运算右值超出了左值类型的表示范围，把该右值截断后赋给左值，所得结果可能毫无意义

    int d = (int)23.59;                                     // 降低了精度。
    cout << "d = " << d << endl;                            //d = 23
    unsigned int e = (unsigned int)4294967295 + 10;         // 值被截断，从高位截断
    cout << "e = " << e << endl;

    // 4294967295     11111111111111111111111111111111
    // 4294967296 000100000000000000000000000000000000
    // 4294967297 000100000000000000000000000000000001


    // 1）为名称复杂的类型创建别名，方便书写和记忆。
    // 2）创建与平台无关的数据类型，提高程序的兼容性。
    // 在 VS 中，short 是两个字节，int 是四个字节，long 也是四个字节，long long 是八个字节。
    typedef short int16_t;            //16位整数
    typedef int int32_t;              //32位整数
    typedef long long int64_t;        //64位整数
    // 在 Linux 中，short 是两个字节，int 是四个字节，long 也是八个字节，long long 也是八个字节。
    // 在程序源代码中，只使用别名 int16_t、int32_t、int64_t，不使用原名。
} 